﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;

namespace PControl
{
    /// <summary>
    /// 自定义带坐标的图形显示控件
    /// </summary>
    public partial class XYForm : UserControl
    {
        #region **private param**
        /// <summary>
        /// 图形显示去横坐标起始、终点值
        /// </summary>
        private int xStartValue = 0, xEndValue = 100;
        /// <summary>
        /// 图形显示去纵坐标起始、终点值
        /// </summary>
        private int yStartValue = 0, yEndValue = 100;
        /// <summary>
        /// 横坐标显示标签
        /// </summary>
        private String xLabel = "X";
        /// <summary>
        /// 纵坐标显示标签
        /// </summary>
        private String yLabel = "Y";
        /// <summary>
        /// 默认滚动显示内容
        /// </summary>
        private String scrollStr="当前高度=0mm 激光功率=0% 单层厚度=0mm 扫描间隔=0mm 扫描速度=0mm/s";

        /// <summary>
        /// 背景色渐进起始颜色
        /// </summary>
        private Color backColorStart = Color.White;
        /// <summary>
        /// 背景色渐进终止颜色
        /// </summary>
        private Color backColorEnd = Color.Gray;
        /// <summary>
        ////坐标线颜色 
        /// </summary>
        private Color coordinateLineColor = Color.Black;
        /// <summary>
        /// 坐标值颜色
        /// </summary>
        private Color coordinateValueColor = Color.Black;
        /// <summary>
        /// 坐标标题颜色
        /// </summary>
        private Color coordinateTitleColor = Color.Black;
        /// <summary>
        /// 主显示区背景色
        /// </summary>
        private Color backColor = Color.FromArgb(34, 88, 150);
        /// <summary>
        /// 模型起始高度
        /// </summary>
        private int layerMiniHight = 0;
        /// <summary>
        /// 模型顶层高度
        /// </summary>
        private int layerMaxiHight = 100;
        /// <summary>
        /// 当前显示层高度
        /// </summary>
        private int layerHight=0;
        #endregion

        public XYForm()
        {
            InitializeComponent();
        }

        #region **get and set**
        [Description("get or set x axis start value of this control\n获取或设置控件x轴起始坐标值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int XStartValue
        {
            get
            {
                return xStartValue;
            }
            set
            {
                xStartValue = value;
                if (xStartValue > xEndValue)
                    xStartValue = xEndValue;
                xAxis.Refresh();
            }
        }

        [Description("get or set x axis end value of this control\n获取或设置控件x轴终止坐标值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int XEndValue
        {
            get
            {
                return xEndValue;
            }
            set
            {
                xEndValue = value;
                if (xEndValue < xStartValue)
                    xEndValue = xStartValue;
                xAxis.Refresh();
            }
        }

        [Description("get or set y axis start value of this control\n获取或设置控件x轴起始坐标值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int YStartValue
        {
            get
            {
                return yStartValue;
            }
            set
            {
                yStartValue = value;
                if (yStartValue > yEndValue)
                    yStartValue = yEndValue;
                yAxis.Refresh();
            }
        }

        [Description("get or set y axis end value of this control\n获取或设置控件x轴终止坐标值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int YEndValue
        {
            get
            {
                return yEndValue;
            }
            set
            {
                yEndValue = value;
                if (yEndValue < yStartValue)
                    yEndValue = yStartValue;
                yAxis.Refresh();
            }
        }

        [Description("get or set x axis label text of this control\n获取或设置控件x轴标签文本")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public String XLabel
        {
            get
            {
                return xLabel;
            }
            set
            {
                xLabel = value;
                x_Label.Text = xLabel + "   ";
            }
        }

        [Description("get or set y axis label text of this control\n获取或设置控件y轴标签文本")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public String YLabel
        {
            get
            {
                return yLabel;
            }
            set
            {
                yLabel = value;
                y_Label.Text = yLabel;
            }
        }

        [Description("get or set scroll label text of this control\n获取或设置滚动显示控件的文本内容")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public String ScrollText
        {
            get
            {
                return scrollStr;
            }
            set
            {
                scrollStr = value;
                location = new Point(5, 0);
                timer.Start();
            }
        }

        [Description("get or set main frame color of this control\n获取或设置控件主显示区背景色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color FrameBackColor
        {
            get
            {
                return backColor;
            }
            set
            {
                backColor = value;
                formFrame.BackColor=backColor;
            }
        }

        [Description("get or set the mini layer hight of this control displaying model\n获取或设置控件显示模型的底层高度值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int LayerMiniHight
        {
            get
            {
                return layerMiniHight;
            }
            set
            {
                layerMiniHight = value;
                vpLayer.Minimum = layerMiniHight;
            }
        }

        [Description("get or set the maxi layer hight of this control displaying model\n获取或设置控件显示模型的顶层高度值")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int LayerMaxiHight
        {
            get
            {
                return layerMaxiHight;
            }
            set
            {
                layerMaxiHight = value;
                vpLayer.Maximum = layerMaxiHight;
            }
        }

        [Description("get or set the layer hight of this control displaying layer\n获取或设置控件y轴标签文本")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public int LayerHight
        {
            get
            {
                return layerHight;
            }
            set
            {
                layerHight = value;
                vpLayer.Value = layerHight;
            }
        }

        [Description("get or set the start color of the gradient background of this control displaying layer\n获取或设置控件渐变色背景的起始颜色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color BackColorStart
        {
            get { return backColorStart; }
            set 
            { 
                backColorStart = value;
                xAxis.Refresh();
                yAxis.Refresh();
            }
        }

        [Description("get or set the end color of the gradient background of this control displaying layer\n获取或设置控件渐变色背景的结束颜色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color BackColorEnd
        {
            get { return backColorEnd; }
            set
            {
                backColorEnd = value;
                xAxis.Refresh();
                yAxis.Refresh();
            }
        }

        [Description("get or set the coordinateline color of this control\n获取或设置控件坐标线颜色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color CoordinateLineColor
        {
            get { return coordinateLineColor; }
            set
            {
                coordinateLineColor = value;
                xAxis.Refresh();
                yAxis.Refresh();
            }
        }

        [Description("get or set the coordinate value color of this control\n获取或设置控件坐标值颜色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color CoordinateValueColor
        {
            get { return coordinateValueColor; }
            set
            {
                coordinateValueColor = value;
                xAxis.Refresh();
                yAxis.Refresh();
            }
        }

        [Description("get or set the coordinate title color of this control\n获取或设置控件坐标标题颜色")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public Color CoordinateTitleColor
        {
            get { return coordinateTitleColor; }
            set
            {
                coordinateTitleColor = value;
                x_Label.ForeColor = y_Label.ForeColor = value;
            }
        }

        [Description("get a pictureBox from this control displaying layer\n从该控件中获取一个PictureBox控件")]
        [Category("XYForm")]
        [RefreshProperties(RefreshProperties.All)]
        public PictureBox GetPictureBox()
        {
            return formFrame;
        }
        #endregion

        #region **私有函数 X轴区域Paint **
        private void xAxis_Paint(object sender, PaintEventArgs e)
        {
            Console.WriteLine("pictureBoxBottom_Paint()+1");
            #region **参数初始化**
            int width = formFrame.Width;
            int height = formFrame.Height;
            float linesNum;                             //可以分成的线段
            float pxLine;                               //每段坐标线间隔
            float pxwidth;                              //所要画坐标的像素范围
            float pxtext;                               //相邻刻度坐标显示值之差
            int currentI;                               //临时，循环用变量
            float currentDrawThick;                     //临时，循环用变量，画坐标线和坐标值
            float currentDrawThin;                      //临时，循环用变量，画坐标线和坐标值
            int showText;                               //要显示的坐标值
            Graphics Grap = e.Graphics;
            #endregion

            using (LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, xAxis.Width, xAxis.Height),
                backColorStart, backColorEnd, 90, false))
            using (Pen penThick = new Pen(coordinateLineColor, 2f))
            using (Pen penThin = new Pen(coordinateLineColor, 1f))
            using (SolidBrush brushString = new SolidBrush(coordinateValueColor))
            using (StringFormat format = new StringFormat())
            using (Font fontThick = new Font("宋体", 12))
            using (Font fontThin = new Font("宋体", 9))
            {
                #region **画背景色**
                Grap.FillRectangle(brush, e.ClipRectangle);
                #endregion

                #region **画坐标**
                //从左往右画

                #region **参数初始化**
                format.LineAlignment = StringAlignment.Near;    //文字垂直上对齐
                format.Alignment = StringAlignment.Center;      //文字水平居中对齐
                linesNum = width / 75;                                 //当前权值下可分为多少段坐标
                pxwidth = (float)width;                                                  //所要画坐标的像素范围
                pxLine = pxwidth / linesNum;                                                    //每段坐标线间隔
                pxtext = (xEndValue - xStartValue) / linesNum;
                #endregion

                #region **第一层坐标**
                //开始画第一层坐标，显示坐标值
                currentI = (int)linesNum + 1;
                showText = xStartValue;
                currentDrawThick = -1 * (penThick.Width / 2) + 50;
                Grap.DrawLine(new Pen(penThick.Color, penThick.Width), 51, 0, 51, 6);         //画第一条坐标线
                Grap.DrawString(showText + "", fontThick, brushString, 51, 6, format);//画第一个坐标值
                for (int i = 1; i < currentI; i++)
                {
                    showText = xStartValue+(int)(pxtext*i);        //更新要画的坐标值
                    currentDrawThick += pxLine;         //更新坐标线和坐标值的位置
                    Grap.DrawLine(penThick, currentDrawThick, 0, currentDrawThick, 6);                                  //画坐标线
                    Grap.DrawString(showText+"", fontThick, brushString, currentDrawThick, 6, format);     //画坐标值
                }
                #endregion

                #region **第二层坐标 5等分**
                //第二层坐标,第一层坐标的基础上10等分
                if (pxLine > 375)
                {
                    #region **参数初始化**
                    pxLine = pxLine / 5f;
                    linesNum = linesNum * 5f;
                    #endregion
                    //开始画第二层坐标，显示坐标值
                    currentI = (int)linesNum + 1;
                    showText = xStartValue;
                    currentDrawThin = -1 * (penThin.Width / 2) + 50;
                    Grap.DrawLine(new Pen(penThick.Color, penThick.Width), 51, 0, 51, 6);         //画第一条坐标线
                    Grap.DrawString(((int)showText).ToString(), fontThick, brushString, 51, 6, format);//画第一个坐标值
                    for (int i = 1; i < currentI; i++)
                    {
                        showText = xStartValue+(int)(pxtext*i);
                        currentDrawThick += pxLine;
                        currentDrawThin += pxLine;
                        if (i % 10 != 0)
                        {
                            Grap.DrawLine(penThin, currentDrawThin, 0, currentDrawThin, 4);  //画坐标线
                            Grap.DrawString(showText + "", fontThin, brushString, currentDrawThin, 6, format); //画坐标值
                        }
                    }
                }
                #endregion
                #region **第二层坐标 2等分**
                //第二层坐标,第一层坐标的基础上10等分
                else if (pxLine > 150)
                {
                    #region **参数初始化**
                    linesNum = linesNum * 2f;
                    pxLine = pxLine / 2f;
                    #endregion
                    //开始画第二层坐标，显示坐标值
                    currentI = (int)linesNum + 1;
                    showText = xStartValue;
                    currentDrawThin = -1 * (penThin.Width / 2) + 50;
                    Grap.DrawLine(new Pen(penThick.Color, penThick.Width), 51, 0, 51, 6);         //画第一条坐标线
                    Grap.DrawString(((int)showText).ToString(), fontThick, brushString, 51, 6, format);//画第一个坐标值
                    for (int i = 1; i < currentI; i++)
                    {
                        showText = xStartValue + (int)(pxtext * i);
                        currentDrawThick += pxLine;
                        currentDrawThin += pxLine;
                        if (i % 5 != 0)
                        {
                            Grap.DrawLine(penThin, currentDrawThin, 0, currentDrawThin, 4);  //画坐标线
                            Grap.DrawString(showText + "", fontThin, brushString, currentDrawThin, 6, format); //画坐标值
                        }
                    }
                }
                #endregion
                #endregion
            }
        }
        #endregion

        #region **私有函数 Y轴区域Paint **
        private void yAxis_Paint(object sender, PaintEventArgs e)
        {
            Console.WriteLine("pictureBoxLeft_Paint()+1");
            #region **参数初始化**
            int width = formFrame.Width;
            int height = formFrame.Height;
            float linesNum;                             //可以分成的线段
            float pxLine;                               //每段坐标线间隔
            float pxheight;                             //所要画坐标的像素范围
            float pxtext;                               //相邻刻度坐标显示值之差
            int currentI;                               //临时，循环用变量
            float currentDrawThick;                     //临时，循环用变量，画坐标线和坐标值
            float currentDrawThin;                     //临时，循环用变量，画坐标线和坐标值
            int showText;                          //要显示的坐标值，decimal能够精确显示坐标值
            Graphics Grap = e.Graphics;
            #endregion

            using (SolidBrush brush = new SolidBrush(backColorStart))
            using (Pen penThick = new Pen(coordinateLineColor, 2f))
            using (Pen penThin = new Pen(coordinateLineColor, 1f))
            using (SolidBrush brushString = new SolidBrush(coordinateValueColor))
            using (StringFormat format = new StringFormat())
            using (Font fontThick = new Font("宋体", 12))
            using (Font fontThin = new Font("宋体", 9))
            {
                #region **画背景色**
                Grap.FillRectangle(brush, e.ClipRectangle);
                this.CreateGraphics().FillRectangle(brush,0,0,Width,Height);
                #endregion

                #region **画坐标**
                //从下往上画

                #region **参数初始化**
                format.LineAlignment = StringAlignment.Center;    //文字垂直居中对齐
                format.Alignment = StringAlignment.Far;      //文字水平右对齐
                linesNum = height / 75;                                 //当前权值下可分为多少段坐标
                pxheight = (float)height;                                                  //所要画坐标的像素范围
                pxLine = pxheight / linesNum;                                                    //每段坐标线间隔
                pxtext = (yEndValue - yStartValue) / linesNum;
                #endregion

                #region **第一层坐标**
                //开始画第一层坐标，显示坐标值
                currentI = (int)linesNum + 1;
                showText = yStartValue;
                currentDrawThick = -1 * (penThick.Width / 2) + yAxis.Height;
                SizeF sizeF = Grap.MeasureString(showText + "", fontThick);
                Grap.DrawLine(penThick, 44, currentDrawThick, 50, currentDrawThick);                                  //画坐标线
                Grap.DrawString(showText + "", fontThick, brushString, 44 - (int)(sizeF.Width * 0.02), currentDrawThick - 5, format);     //画坐标值
                for (int i = 1; i < currentI - 1; i++)
                {
                    showText = yStartValue + (int)(pxtext * i);        //更新要画的坐标值
                    currentDrawThick -= pxLine;         //更新坐标线和坐标值的位置
                    sizeF = Grap.MeasureString(showText + "", fontThick);
                    Grap.DrawLine(penThick, 44, currentDrawThick, 50, currentDrawThick);                                  //画坐标线
                    Grap.DrawString(showText + "", fontThick, brushString, 44 - (int)(sizeF.Width * 0.02), currentDrawThick, format);     //画坐标值
                }
                showText = yEndValue;
                currentDrawThick -= pxLine;
                currentDrawThick += 2;//坐标补偿
                sizeF = Grap.MeasureString(showText + "", fontThick);
                Grap.DrawLine(penThick, 44, currentDrawThick, 50, currentDrawThick);
                Grap.DrawString(showText + "", fontThick, brushString, 44 - (int)(sizeF.Width * 0.02), currentDrawThick, format);
                #endregion

                #region **第二层坐标 5等分**
                //第二层坐标,第一层坐标的基础上5等分
                if (pxLine > 375)
                {
                    #region **参数初始化**
                    linesNum = linesNum * 5f;
                    pxLine = pxLine / 5f;
                    #endregion
                    //开始画第二层坐标，显示坐标值
                    currentI = (int)linesNum + 1;
                    showText = yStartValue;
                    currentDrawThin = -1 * (penThin.Width / 2) + yAxis.Height;
                    for (int i = 1; i < currentI - 1; i++)
                    {
                        showText = yStartValue + (int)(pxtext * i);        //更新要画的坐标值
                        currentDrawThin -= pxLine;
                        if (i % 10 != 0)
                        {
                            sizeF = Grap.MeasureString(showText + "", fontThin);
                            Grap.DrawLine(penThin, 46, currentDrawThin, 50, currentDrawThin);  //画坐标线
                            Grap.DrawString(showText + "", fontThin, brushString, 44 - (int)(sizeF.Width * 0.02), currentDrawThin, format); //画坐标值
                        }
                    }
                }
                #endregion
                #region **第二层坐标 2等分**
                //第二层坐标,第一层坐标的基础上2等分
                else if (pxLine > 150)
                {
                    #region **参数初始化**
                    linesNum = linesNum * 2f;
                    pxLine = pxLine / 2f;
                    #endregion
                    //开始画第二层坐标，显示坐标值
                    currentI = (int)linesNum + 1;
                    showText = yStartValue;
                    currentDrawThin = -1 * (penThin.Width / 2) + yAxis.Height;
                    for (int i = 1; i < currentI - 1; i++)
                    {
                        showText = yStartValue + (int)(pxtext * i);        //更新要画的坐标值
                        currentDrawThin -= pxLine;
                        if (i % 5 != 0)
                        {
                            sizeF = Grap.MeasureString(showText + "", fontThin);
                            Grap.DrawLine(penThin, 46, currentDrawThin, 50, currentDrawThin);  //画坐标线
                            Grap.DrawString(showText + "", fontThin, brushString, 44 - (int)(sizeF.Width * 0.02), currentDrawThin, format); //画坐标值
                        }
                    }
                }
                #endregion
                #endregion
            }
        }
        #endregion


        private Point location = new Point(5, 0);
        #region 滚动字体显示
        private void lbScrollText_Paint(object sender, PaintEventArgs e)
        {
            Graphics grap = e.Graphics;
            Pen penThick = new Pen(Color.Black, 2f);
            Font font = new Font("华文新魏", 12F);
            SolidBrush brushString = new SolidBrush(Color.Black);
            StringFormat format = new StringFormat();
            float StrWidth = grap.MeasureString(scrollStr, font).Width;
            if (StrWidth < lbScrollText.Width)
            {
                timer.Stop();
                lbScrollText.Text = scrollStr;
            }
            else
            {
                lbScrollText.Text = "";
                location.X -= 10;
                if (location.X + StrWidth < lbScrollText.Width)
                    location.X = lbScrollText.Width / 2;
                grap.DrawString(scrollStr, font, brushString, location.X, location.Y, format);
            }
        }
        #endregion
        #region 控件相关事件
        private void XYForm_Load(object sender, EventArgs e)
        {
            timer_Tick(sender, e);
        }

        private void XYForm_Resize(object sender, EventArgs e)
        {
            xAxis.Refresh();
            yAxis.Refresh();
            lbScrollText.Width = this.Width - x_Label.Width;
        }

        private void XYForm_SizeChanged(object sender, EventArgs e)
        {
            location = new Point(lbScrollText.Width / 2, 0);
            timer.Start();
        }
        /// <summary>
        /// 鼠标点击后显示坐标值
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void formFrame_MouseDown(object sender, MouseEventArgs e)
        {
            StringBuilder str = new StringBuilder();
            str.Append("x=");
            str.Append((float)e.X / formFrame.Width * (xEndValue - xStartValue));
            str.Append(" , y=");
            str.Append((float)(formFrame.Height - e.Y) / formFrame.Height * (yEndValue - yStartValue));
            mouseLocationg.SetToolTip(formFrame,str.ToString());
            str = null;
        }
        #endregion
        private void timer_Tick(object sender, EventArgs e)
        {
            lbScrollText.Refresh();
            //if(location.X==5)
            //    Thread.Sleep(1000); ;
        }
    }
}
